//
// Created by martin on 2/13/22.
//

#include "EventLoopThread.h"
#include "muduo/net/EventLoop.h"

using namespace muduo;
using namespace muduo::net;

EventLoopThread::EventLoopThread(const EventLoopThread::ThreadInitCallback &cb, const string &name)
: loop_(NULL),
  exiting_(false),
  thread_(std::bind(&EventLoopThread::threadFunc, this), name), // 注意这里只是注册线程函数, 名称, 并未启动线程函数
  mutex_(),
  cond_(mutex_),
  callback_(cb)
{
}

EventLoopThread::~EventLoopThread()
{
    exiting_ = true;
    // 不是100%没有冲突, 比如threadFunc中正运行callback_回调, 然后立即析构当前对象.
    // 此时, IO线程函数已经启动, 创建EventLoop了对象, 但还没有修改loop_, 此时loop_一直为NULL
    // 也就是说, 无法通过析构让IO线程退出loop循环, 也无法连接线程.
    if (loop_ != NULL) // not 100% race-free, eg. threadFunc could be running callback_
    {
        // sitll a tiny change to call destructed object, if threadFunc exists just now.
        // but when EventLoopThread destructs, usually programming is exiting anyway.
        loop_->quit(); // 退出IO线程loop循环
        thread_.join(); // 连接线程, 回收资源
    }
}

/**
 * 启动IO线程(函数), 运行EventLoop循环
 * @return 返回EventLoop*, 实际上是线程函数threadFunc创建的EventLoop类型局部变量
 */
EventLoop* EventLoopThread::startLoop()
{
    assert(!thread_.started()); // avoid repeated start loop
    thread_.start(); // 启动线程

    EventLoop* loop = NULL;
    {
        MutexLockGuard lock(mutex_);
        while (loop_ == NULL)
        {
            cond_.wait();  // 等待线程函数完成初始化工作, 唤醒等待在此处的调用线程
        }
        loop = loop_;
    }

    return loop;
}

/**
 * IO线程函数, 创建EventLoop局部对象, 运行loop循环
 */
void EventLoopThread::threadFunc()
{
    EventLoop loop; // 创建线程函数局部EventLoop对象, 只有线程函数退出, EventLoop::loop()退出时, 才会释放该对象

    if (callback_) // 运行线程函数初始回调
    {
        callback_(&loop);
    }

    {
        MutexLockGuard lock(mutex_);
        loop_ = &loop;
        cond_.notify(); // 唤醒等待在cond_条件上的线程(i.e. startLoop的调用线程)
    }

    loop.loop(); // 运行IO线程循环, 即事件循环, 通常不会退出, 除非调用EventLoop::quit
    // assert(exiting_);
    MutexLockGuard lock(mutex_);
    loop_ = NULL; // 思考: 最后为什么要清除loop_?
}
